import io
import json
from io import BytesIO

from django.contrib.admin.utils import quote

# Create your views here.
from django.shortcuts import render, redirect

from polls.models import Subject, Teacher, User

from django.http import JsonResponse, HttpResponse, HttpRequest
import xlwt
from reportlab.pdfgen import canvas
from .utils import gen_random_code, gen_md5_digest
from .captcha import Captcha

from polls.mappers import SubjectMapper
from polls.models import Subject

from rest_framework.decorators import api_view
from rest_framework.response import Response

from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import ListAPIView
from django.views.decorators.cache import cache_page
from polls.dataSerializer import SubjectSerializer, TeacherSerializer
from rest_framework.authtoken.models import Token

import logging

logger = logging.getLogger("django")

""" 简单的说RESTful架构就是：“每一个URI代表一种资源，客户端通过四个HTTP动词，对服务器端资源进行操作，实现资源的表现层状态转移”。
    URI应该只代表“资源”的位置，它的具体表现形式，应该在HTTP请求的头信息中用Accept和Content-Type字段指定，这两个字段才是对“表现层”的描述。 

    DRF框架支持两种实现数据接口的方式，一种是FBV（基于函数的视图），另一种是CBV（基于类的视图）。
    使用CBV创建数据接口的特点是代码简单，开发效率高，但是没有FBV（基于函数的视图）灵活，
    因为使用FBV的方式，数据接口对应的视图函数执行什么样的代码以及返回什么的数据是高度可定制的。"""


# CBV的方式实现数据接口 - 继承ModelViewSet 、ReadOnlyModelViewSet
# 如果学科对应的数据接口需要支持GET、POST、PUT、PATCH、DELETE请求来支持对学科资源的获取、新增、更新、删除操作，更为简单的做法是继承ModelViewSet来编写学科视图类。
class SubjectViewSet(ModelViewSet):
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializer


# CBV的方式实现数据接口 - 继承ListAPIView
# ListAPIView能接收GET请求，它封装了获取数据列表并返回JSON数据的get方法。ListAPIView是APIView 的子类，
# APIView还有很多的子类，例如CreateAPIView可以支持POST请求，UpdateAPIView可以支持PUT和PATCH请求，DestoryAPIView可以支持DELETE请求
class Subject_ListAPIView(ListAPIView):
    # 通过queryset指定如何获取学科数据
    queryset = Subject.objects.all()
    # 通过serializer_class指定如何序列化学科数据
    serializer_class = SubjectSerializer


# FBV的方式实现数据接口
@api_view(('GET',))
# 声明式缓存：所谓声明式缓存是指不修改原来的代码，通过Python中的装饰器（代理）为原有的代码增加缓存功能。
@cache_page(timeout=86400, cache='default')
def subjects_fbv(request: HttpRequest) -> HttpResponse:
    subjects = Subject.objects.all().order_by('no')
    # 创建序列化器对象并指定要序列化的模型
    serializer = SubjectSerializer(subjects, many=True)
    # 通过序列化器的data属性获得模型对应的字典并通过创建Response对象返回JSON格式的数据
    return Response(serializer.data)


# ListAPIView能接收GET请求
class TeacherView(ListAPIView):
    serializer_class = TeacherSerializer

    def get_queryset(self):
        queryset = Teacher.objects.defer('sno')
        try:
            sno = self.request.GET.get('sno', '')
            queryset = queryset.filter(sno=sno)
            return queryset
        except ValueError:
            return Response(status=404)


def praise_or_criticize(request):
    print("点赞请求啊啊啊")
    """好评"""
    try:
        tno = request.GET["tno"]
        print("tno data:", tno)
        teacher = Teacher.objects.get(no=tno)
        if request.path.startswith('/praise'):
            teacher.good_count += 1
            count = teacher.good_count
        else:
            teacher.bad_count += 1
            count = teacher.bad_count
        teacher.save()
        return JsonResponse({'code': 20000, 'msg': '投票成功', 'count': count})
    except (ValueError, Teacher.DoseNotExist):
        return JsonResponse({'code': 20001, 'msg': '投票失败'})


def get_captcha(request: HttpRequest) -> HttpResponse:
    """验证码"""
    captcha_text = gen_random_code()
    request.session['captcha'] = captcha_text
    image_data = Captcha.instance().generate(captcha_text)
    return HttpResponse(image_data, content_type='image/png')


def login(request):
    if request.method == 'POST':
        body = json.loads(request.body)
        username = body['username']
        password = body['password']
        if username and password:
            user = User.objects.filter(username=username).first()
            print("login 数据库userb:", user)
            if user:
                # token, created = Token.objects.get_or_create(user=username)
                return JsonResponse({'result': "success", 'msg': '登录成功', "token": username})
            else:
                return JsonResponse({'result': "failed", 'msg': '用户名或密码错误'})
        else:
            print("login AAA CCC")
            return JsonResponse({'result': "rejected", 'msg': '请输入有效的用户名和密码'})


def logout(request):
    """注销"""
    request.session.flush()
    return redirect('/')


def export_teachers_excel(request):
    # 创建工作簿
    wb = xlwt.Workbook()
    # 添加工作表
    sheet = wb.add_sheet('老师信息表')
    # 查询所有老师的信息
    queryset = Teacher.objects.all()
    # 向Excel表单中写入表头
    colnames = ('姓名', '介绍', '好评数', '差评数', '学科')
    for index, name in enumerate(colnames):
        sheet.write(0, index, name)
    # 向单元格中写入老师的数据
    props = ('name', 'detail', 'good_count', 'bad_count', 'subject')
    for row, teacher in enumerate(queryset):
        for col, prop in enumerate(props):
            value = getattr(teacher, prop, '')
            if isinstance(value, Subject):
                value = value.name
            sheet.write(row + 1, col, value)
    # 保存Excel
    buffer = BytesIO()
    wb.save(buffer)
    # 将二进制数据写入响应的消息体中并设置MIME类型
    resp = HttpResponse(buffer.getvalue(), content_type='application/vnd.ms-excel')
    # 中文文件名需要处理成百分号编码
    filename = quote('老师.xls')
    # 通过响应头告知浏览器下载该文件以及对应的文件名
    resp['content-disposition'] = f'attachment; filename*=utf-8\'\'{filename}'
    return resp


def export_pdf(request: HttpRequest) -> HttpResponse:
    buffer = io.BytesIO()
    pdf = canvas.Canvas(buffer)
    pdf.setFont("Helvetica", 80)
    pdf.setFillColorRGB(0.2, 0.5, 0.3)
    pdf.drawString(100, 550, 'hello, world!')
    pdf.showPage()
    pdf.save()
    resp = HttpResponse(buffer.getvalue(), content_type='application/pdf')
    resp['content-disposition'] = 'inline; filename="demo.pdf"'
    return resp


def get_teachers_data(request):
    if request.method == "POST":
        # queryset = Teacher.objects.all()
        queryset = Teacher.objects.all().only('name', 'good_count', 'bad_count')
        names = [teacher.name for teacher in queryset]
        good_counts = [teacher.good_count for teacher in queryset]
        bad_counts = [teacher.bad_count for teacher in queryset]
        return JsonResponse({'names': names, 'good': good_counts, 'bad': bad_counts})
    return render(request, 'chart.html')


def echart_view(request):
    if request.method == 'POST':
        data = {}
        categories = ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
        values = [50, 20, 36, 10, 10, 20]
        data['categories'] = categories
        data['values'] = values
        print("data:", data)
        return JsonResponse(data)
    return render(request, 'echart2.html')
